import time
import json
import logging
from django.utils.deprecation import MiddlewareMixin
from django.http import JsonResponse
from django.contrib.auth.models import AnonymousUser
from django.core.cache import cache
from django.conf import settings
from datetime import datetime, timedelta

# 配置日志记录器
logger = logging.getLogger('api_monitor')

class APIMonitoringMiddleware(MiddlewareMixin):
    """API监控中间件"""
    
    def __init__(self, get_response):
        self.get_response = get_response
        # 排除的路径
        self.excluded_paths = [
            '/admin/',
            '/static/',
            '/media/',
            '/favicon.ico',
        ]
    
    def __call__(self, request):
        # 记录请求开始时间
        start_time = time.time()
        
        # 处理请求
        response = self.get_response(request)
        
        # 计算响应时间
        response_time = time.time() - start_time
        
        # 记录API调用信息
        self._log_api_call(request, response, response_time)
        
        # 添加响应时间到头部
        response['X-Response-Time'] = f'{response_time:.3f}s'
        
        return response
    
    def _should_monitor(self, request):
        """判断是否需要监控该请求"""
        path = request.path
        
        # 排除静态资源和管理页面
        for excluded_path in self.excluded_paths:
            if path.startswith(excluded_path):
                return False
        
        # 只监控API请求
        return path.startswith('/api/')
    
    def _log_api_call(self, request, response, response_time):
        """记录API调用日志"""
        if not self._should_monitor(request):
            return
        
        # 获取用户信息
        user_info = 'anonymous'
        if hasattr(request, 'user') and not isinstance(request.user, AnonymousUser):
            user_info = f'{request.user.username}({request.user.id})'
        
        # 获取请求参数
        query_params = dict(request.GET) if request.GET else {}
        
        # 获取请求头中的Content-Type等信息（避免读取body）
        content_type = request.content_type
        request_method = request.method
        
        # 构造日志信息
        log_data = {
            'timestamp': datetime.now().isoformat(),
            'method': request.method,
            'path': request.path,
            'user': user_info,
            'ip': self._get_client_ip(request),
            'user_agent': request.META.get('HTTP_USER_AGENT', '')[:200],
            'status_code': response.status_code,
            'response_time': round(response_time, 3),
            'query_params': query_params,
            'content_type': content_type,
        }
        
        # 记录到日志文件
        if response.status_code >= 400:
            logger.error(f"API_ERROR: {json.dumps(log_data, ensure_ascii=False)}")
        else:
            logger.info(f"API_CALL: {json.dumps(log_data, ensure_ascii=False)}")
        
        # 更新统计缓存
        self._update_stats(request, response, response_time)
    
    def _get_client_ip(self, request):
        """获取客户端IP地址"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip
    
    def _update_stats(self, request, response, response_time):
        """更新统计数据到缓存"""
        try:
            # 获取用户信息
            user_key = 'anonymous'
            if hasattr(request, 'user') and not isinstance(request.user, AnonymousUser):
                user_key = f'user_{request.user.id}'
            
            today = datetime.now().strftime('%Y-%m-%d')
            hour = datetime.now().strftime('%Y-%m-%d-%H')
            
            # 更新每日统计
            daily_key = f'api_stats_daily_{today}'
            hourly_key = f'api_stats_hourly_{hour}'
            user_daily_key = f'api_stats_user_daily_{user_key}_{today}'
            
            # 使用管道操作提高效率
            pipe = cache._cache.pipeline() if hasattr(cache._cache, 'pipeline') else None
            
            stats_keys = [daily_key, hourly_key, user_daily_key]
            
            for key in stats_keys:
                current_stats = cache.get(key, {
                    'total_requests': 0,
                    'success_requests': 0,
                    'error_requests': 0,
                    'total_response_time': 0,
                    'avg_response_time': 0,
                    'max_response_time': 0,
                    'min_response_time': float('inf'),
                    'endpoints': {}
                })
                
                # 更新统计数据
                current_stats['total_requests'] += 1
                if response.status_code < 400:
                    current_stats['success_requests'] += 1
                else:
                    current_stats['error_requests'] += 1
                
                current_stats['total_response_time'] += response_time
                current_stats['avg_response_time'] = current_stats['total_response_time'] / current_stats['total_requests']
                current_stats['max_response_time'] = max(current_stats['max_response_time'], response_time)
                current_stats['min_response_time'] = min(current_stats['min_response_time'], response_time)
                
                # 端点统计
                endpoint = f"{request.method} {request.path}"
                if endpoint not in current_stats['endpoints']:
                    current_stats['endpoints'][endpoint] = {
                        'count': 0,
                        'avg_response_time': 0,
                        'total_response_time': 0
                    }
                
                endpoint_stats = current_stats['endpoints'][endpoint]
                endpoint_stats['count'] += 1
                endpoint_stats['total_response_time'] += response_time
                endpoint_stats['avg_response_time'] = endpoint_stats['total_response_time'] / endpoint_stats['count']
                
                # 缓存统计数据（24小时过期）
                cache.set(key, current_stats, 60 * 60 * 24)
                
        except Exception as e:
            logger.error(f"Failed to update API stats: {str(e)}")


class RateLimitMiddleware(MiddlewareMixin):
    """API限流中间件"""
    
    def __init__(self, get_response):
        self.get_response = get_response
        # 默认限制配置
        self.rate_limits = {
            'default': {'requests': 100, 'window': 60},  # 每分钟100次
            'auth': {'requests': 20, 'window': 60},      # 认证接口每分钟20次
            'upload': {'requests': 10, 'window': 60},    # 上传接口每分钟10次
        }
    
    def __call__(self, request):
        # 检查限流
        if not self._check_rate_limit(request):
            return JsonResponse({
                'error': '请求过于频繁，请稍后再试',
                'error_code': 'RATE_LIMIT_EXCEEDED'
            }, status=429)
        
        response = self.get_response(request)
        return response
    
    def _check_rate_limit(self, request):
        """检查限流"""
        if not request.path.startswith('/api/'):
            return True
        
        # 获取客户端标识
        client_id = self._get_client_id(request)
        
        # 确定限流类型
        limit_type = self._get_limit_type(request)
        limit_config = self.rate_limits.get(limit_type, self.rate_limits['default'])
        
        # 构造缓存key
        window_start = int(time.time()) // limit_config['window']
        cache_key = f"rate_limit_{limit_type}_{client_id}_{window_start}"
        
        # 获取当前请求数
        current_requests = cache.get(cache_key, 0)
        
        # 检查是否超出限制
        if current_requests >= limit_config['requests']:
            return False
        
        # 增加请求计数
        cache.set(cache_key, current_requests + 1, limit_config['window'])
        return True
    
    def _get_client_id(self, request):
        """获取客户端标识"""
        # 优先使用用户ID
        if hasattr(request, 'user') and not isinstance(request.user, AnonymousUser):
            return f"user_{request.user.id}"
        
        # 使用IP地址
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        
        return f"ip_{ip}"
    
    def _get_limit_type(self, request):
        """确定限流类型"""
        path = request.path
        
        if '/auth/' in path or '/token/' in path:
            return 'auth'
        elif '/upload' in path or request.method == 'POST':
            return 'upload'
        else:
            return 'default'


class APIStatsView:
    """API统计视图辅助类"""
    
    @staticmethod
    def get_stats(time_range='today'):
        """获取API统计数据"""
        try:
            stats = {
                'overview': {},
                'endpoints': [],
                'errors': [],
                'performance': {}
            }
            
            if time_range == 'today':
                today = datetime.now().strftime('%Y-%m-%d')
                key = f'api_stats_daily_{today}'
            elif time_range == 'hour':
                hour = datetime.now().strftime('%Y-%m-%d-%H')
                key = f'api_stats_hourly_{hour}'
            else:
                # 默认今日
                today = datetime.now().strftime('%Y-%m-%d')
                key = f'api_stats_daily_{today}'
            
            data = cache.get(key, {})
            
            if data:
                # 概览统计
                stats['overview'] = {
                    'total_requests': data.get('total_requests', 0),
                    'success_requests': data.get('success_requests', 0),
                    'error_requests': data.get('error_requests', 0),
                    'success_rate': round(
                        (data.get('success_requests', 0) / max(data.get('total_requests', 1), 1)) * 100, 2
                    ),
                    'avg_response_time': round(data.get('avg_response_time', 0), 3),
                    'max_response_time': round(data.get('max_response_time', 0), 3),
                    'min_response_time': round(data.get('min_response_time', 0), 3) if data.get('min_response_time', 0) != float('inf') else 0
                }
                
                # 端点统计
                endpoints = data.get('endpoints', {})
                stats['endpoints'] = [
                    {
                        'endpoint': endpoint,
                        'count': info['count'],
                        'avg_response_time': round(info['avg_response_time'], 3)
                    }
                    for endpoint, info in sorted(endpoints.items(), key=lambda x: x[1]['count'], reverse=True)
                ][:10]  # 取前10个
            
            return stats
            
        except Exception as e:
            logger.error(f"Failed to get API stats: {str(e)}")
            return {
                'overview': {},
                'endpoints': [],
                'errors': [],
                'performance': {}
            }